package com.southminority.ethnic.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.southminority.ethnic.common.context.UserContext;
import com.southminority.ethnic.common.result.R;
import com.southminority.ethnic.pojo.User;
import com.southminority.ethnic.service.token.TokenService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * Token验证拦截器
 * 用于在每个HTTP请求中验证token并设置用户上下文
 * 
 * @author SouthMinority
 */
@Slf4j
@Component
public class TokenAuthenticationInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ObjectMapper objectMapper;

    // 不需要验证token的路径
    private static final List<String> EXCLUDE_PATHS = Arrays.asList(
        "/admin",   
        "/vipadmin",     
        "/aliyunOss" 
    );

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //log.info("=== Token验证拦截器开始执行 ===");
        
        // 获取请求路径
        String requestPath = request.getRequestURI();
        //log.info("请求路径: {}", requestPath);
        
        // 检查是否是不需要验证token的路径
        if (!isExcludePath(requestPath)) {
            //如果token不为空，添加用户到UserContext中
                // 从请求头中获取token
                String token = extractTokenFromRequest(request);
                if (token!=null&&!"".equals(token)) {

                    //log.info("提取到的token: {}", token != null ? token.substring(0, Math.min(20, token.length())) + "..." : "null")
                    // 验证token
                    User user = tokenService.validateToken(token);
                    //log.info("Token验证结果: {}", user != null ? "成功" : "失败");

                    if (user == null) {
                        //log.warn("Token验证失败: {}", token);
                        log.info("非拦截路径下，Token验证失败，但允许访问: {}", requestPath);
                        // 注意：不调用 sendUnauthorizedResponse，因为非拦截路径允许匿名访问
                    }else {
                        log.info("非拦截下，用户已经登录;userId："+user.getId()+";访问路径："+requestPath);
                        // 设置用户上下文
                        UserContext.setCurrentUser(user);
                    }

                }else{
                    log.info("用户的token不存在，允许匿名访问: {}", requestPath);
                }

            return true;
        }

        //log.info("开始验证token: {}", requestPath);

        try {
            // 从请求头中获取token
            String token = extractTokenFromRequest(request);
            //log.info("提取到的token: {}", token != null ? token.substring(0, Math.min(20, token.length())) + "..." : "null");

            if (!StringUtils.hasText(token)) {
                //log.warn("请求缺少token: {}", requestPath);
                sendUnauthorizedResponse(response, "缺少认证token");
                return false;
            }

            // 验证token
            User user = tokenService.validateToken(token);
            //log.info("Token验证结果: {}", user != null ? "成功" : "失败");

            if (user == null) {
                //log.warn("Token验证失败: {}", token);
                sendUnauthorizedResponse(response, "Token无效或已过期");
                return false;
            }

            //log.info("用户信息: ID={}, 用户名={}, 用户类型={}",
            //    user.getId(), user.getUsername(), user.getUserType());

            // 设置用户上下文
            UserContext.setCurrentUser(user);
            //log.info("用户上下文设置完成");
            
            // 检查是否需要刷新token
            String newToken = tokenService.refreshTokenIfNeeded(token);
            if (!newToken.equals(token)) {
                // 在响应头中返回新token
                response.setHeader("New-Token", newToken);
                response.setHeader("Access-Control-Expose-Headers", "New-Token");
                //log.info("Token已刷新");
            }

            //log.info("Token验证成功，用户: {}, 路径: {}", user.getEmail(), requestPath);
            return true;

        } catch (Exception e) {
            //log.error("Token验证异常", e);
            sendUnauthorizedResponse(response, "认证失败：" + e.getMessage());
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清理用户上下文
        UserContext.clear();
    }

    /**
     * 从请求中提取token
     */
    private String extractTokenFromRequest(HttpServletRequest request) {
        // 优先从Authorization头获取
        String authHeader = request.getHeader("Authorization");
        if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }

        // 从token参数获取
        String tokenParam = request.getParameter("token");
        if (StringUtils.hasText(tokenParam)) {
            return tokenParam;
        }

        // 从自定义头获取
        String customToken = request.getHeader("X-Token");
        if (StringUtils.hasText(customToken)) {
            return customToken;
        }

        return null;
    }

    /**
     * 检查是否为排除路径
     */
    private boolean isExcludePath(String requestPath) {
        return EXCLUDE_PATHS.stream().anyMatch(requestPath::startsWith);
    }

    /**
     * 发送未授权响应
     */
    private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        
        R<Void> result = R.fail(401, message);
        response.getWriter().write(objectMapper.writeValueAsString(result));
    }
} 